﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;

namespace suirui.ZhuMu.Common
{
    /// <summary>
    ///泛型委托基于泛型类之上
    ///泛型静态类在确定参数类型的时候会调用其静态函数
    ///在执行委托时，泛型委托会内置查找相应的委托来执行
    /// </summary>
    public static class ExpressionAndFuncMethod<TModel, TModelDto>
       where TModel : class
       where TModelDto : class
    {
        static ExpressionAndFuncMethod()
        {
            ExpressionMapper();
        }

        public static Func<TModelDto, TModel> _func = null;

        public static void ExpressionMapper()
        {
            Type modelType = typeof(TModel);
            Type modelDtoType = typeof(TModelDto);

            //创建一个lambda参数x，定义的对象为TModelDto
            ParameterExpression parameterExpression = Expression.Parameter(modelDtoType, "x");
            //开始生成lambda表达式
            List<MemberBinding> list = new List<MemberBinding>();
            foreach (var item in modelType.GetProperties())
            {
                //为x参数表达式生成一个属性值
                MemberExpression property = Expression.Property(parameterExpression, modelDtoType.GetProperty(item.Name));
                //将该属性初始化 eg:No=x.No
                MemberBinding memberBinding = Expression.Bind(item, property);
                list.Add(memberBinding);
            }

            foreach (var item in typeof(TModel).GetFields())
            {
                //为x参数表达式生成一个字段值
                MemberExpression field = Expression.Field(parameterExpression, modelDtoType.GetField(item.Name));
                //将该字段初始化
                MemberBinding memberBinding = Expression.Bind(item, field);
                list.Add(memberBinding);
            }
            //调用构造函数，初始化一个TModel eg: new{No=x.No...}
            MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(modelType), list);
            //创建lambda表达式  eg: x=>new{ No=x.No...}
            Expression<Func<TModelDto, TModel>> lambda = Expression.Lambda<Func<TModelDto, TModel>>(memberInitExpression, parameterExpression);
            //将lambda表达式生成委托
            _func = lambda.Compile();
        }

        public static TModel Trans(TModelDto dto)
        {
            if (_func != null)
                return _func(dto);
            return default(TModel);
        }
    }
}
